package com.cooldatasoft.taskManager.user.gui;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;

import com.cooldatasoft.domain.model.Project;
import com.cooldatasoft.domain.model.Roles;
import com.cooldatasoft.domain.model.RolesEnum;
import com.cooldatasoft.domain.model.Task;
import com.cooldatasoft.domain.model.User;
import com.cooldatasoft.domain.model.UserProjectRoles;
import com.cooldatasoft.domain.service.ProjectsService;
import com.cooldatasoft.domain.service.RolesService;
import com.cooldatasoft.domain.service.TaskService;
import com.cooldatasoft.domain.service.UserProjectRolesService;
import com.cooldatasoft.domain.service.UserService;
import com.cooldatasoft.security.TaskManagerSecurityManager;
import com.cooldatasoft.taskManager.MainPage;
import com.cooldatasoft.taskManager.component.TaskManagerNotification;
import com.vaadin.annotations.AutoGenerated;
import com.vaadin.data.Item;
import com.vaadin.data.util.HierarchicalContainer;
import com.vaadin.event.Action;
import com.vaadin.event.ItemClickEvent;
import com.vaadin.event.ItemClickEvent.ItemClickListener;
import com.vaadin.ui.AbsoluteLayout;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.CustomComponent;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.Label;
import com.vaadin.ui.ListSelect;
import com.vaadin.ui.TabSheet;
import com.vaadin.ui.Tree;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.Window;
import com.vaadin.ui.Window.Notification;
import com.vaadin.ui.themes.Reindeer;

@Configurable(preConstruction = true)
public class LeftPanel extends CustomComponent {

	@AutoGenerated
	private AbsoluteLayout mainLayout;
	@AutoGenerated
	private VerticalLayout verticalLayout_1;
	@AutoGenerated
	private Label label_1;

	/*- VaadinEditorProperties={"grid":"RegularGrid,20","showGrid":true,"snapToGrid":true,"snapToObject":true,"movingGuides":false,"snappingDistance":10} */

	/*- VaadinEditorProperties={"grid":"RegularGrid,20","showGrid":true,"snapToGrid":true,"snapToObject":true,"movingGuides":false,"snappingDistance":10} */

	private static final long serialVersionUID = 1L;
	@Autowired
	TaskManagerSecurityManager securityManager;
	@Autowired
	UserProjectRolesService userProjectRolesService;
	@Autowired
	RolesService rolesService;
	@Autowired
	UserService userService;
	@Autowired
	ProjectsService projectService;
	@Autowired
	TaskService taskService;

	protected Tree treetable;
	private List<Project> projects;
	
	protected MainPage mainPage;
	private static final Action ADD = new Action("Assign user");
	private static final Action DELETE = new Action("Delete user from project");
	private static final Action DELETE_PROJECT = new Action("Delete project");
	private HierarchicalContainer container;

	public LeftPanel(MainPage mainPage_in) {
		mainPage = mainPage_in;
		buildMainLayout();
		setCompositionRoot(mainLayout);
        projects = new ArrayList<Project>();
        
		createTreeTable();
		verticalLayout_1.addComponent(treetable);
		verticalLayout_1.setExpandRatio(treetable, 1.0f);
		label_1.setStyle(Reindeer.LABEL_H2);
	}

	public void removeItemFromTree(Project project) {
		Object itemId = null;
		for (Object object : treetable.rootItemIds()) {
			Project projectHelp = (Project) container.getItem(object)
					.getItemProperty("project").getValue();
			if (projectHelp.getIdProject() == project.getIdProject()) {
				itemId = object;
			}
		}

		container.removeItemRecursively(itemId);
	}

	public void addItemToTree(Project project) {
		
		for (Project alreadyInsertedProject : projects) {
			if (alreadyInsertedProject.getIdProject() == project.getIdProject()) {
				return;
			}
		}
		
		List<Roles> roles = rolesService.getAllRoles();

		Object projectItemId = null;
		Object roleItemId = null;
		Object userItemId = null;

		List<UserProjectRoles> userss = new ArrayList<UserProjectRoles>();
		projectItemId = treetable.addItem();

		container.getItem(projectItemId).getItemProperty("project")
				.setValue(project);
		treetable.setItemCaption(projectItemId, container
				.getItem(projectItemId).getItemProperty("project").getValue()
				.toString());

		treetable.setParent(projectItemId, null);

		for (Roles role : roles) {

			roleItemId = treetable.addItem();
			container.getItem(roleItemId).getItemProperty("role")
					.setValue(role);
			treetable.setItemCaption(roleItemId, container.getItem(roleItemId)
					.getItemProperty("role").getValue().toString());
			treetable.getChildren(roleItemId);

			treetable.setParent(roleItemId, projectItemId);
			treetable.setChildrenAllowed(roleItemId, (roles.size() > 0) ? true
					: false);
			userss.clear();

			if (userProjectRolesService.getUsersByRoleOnProject(project, role) != null) {
				userss.addAll(userProjectRolesService.getUsersByRoleOnProject(
						project, role));

				for (UserProjectRoles u : userss) {
					userItemId = treetable.getContainerDataSource().addItem();
					container.getItem(userItemId).getItemProperty("user")
							.setValue(u.getIdUser());
					treetable.setItemCaption(
							userItemId,
							container.getItem(userItemId)
									.getItemProperty("user").getValue()
									.toString());
					treetable.setChildrenAllowed(userItemId, false);

					container.setParent(userItemId, roleItemId);
				}
			} else {
				userItemId = treetable.getContainerDataSource().addItem();
				treetable.setItemCaption(userItemId, "");
				treetable.setChildrenAllowed(userItemId, false);

				container.setParent(userItemId, roleItemId);
			}
		}
		
		projects.add(project);
	}

	public void createTreeTable() {
		// Create the treetable
		treetable = new Tree();
		treetable.setWidth("100.0%");
		treetable.setHeight("100.0%");
		treetable.setStyleName("leftTree");

		container = new HierarchicalContainer();
		container.addContainerProperty("project", Project.class, null);
		container.addContainerProperty("role", Roles.class, null);
		container.addContainerProperty("user", User.class, null);

		// Add Table columns
		treetable.setContainerDataSource(container);
		treetable.setImmediate(true);

		treetable.addActionHandler(new Action.Handler() {

			private static final long serialVersionUID = 1L;

			public void handleAction(Action action, Object sender,
					final Object target) {
				if (action == ADD) {
					handleAddAction(target);	
				} 
				else if (action == DELETE) {
					handleDeleteAction(target);
				} 
				else if (action == DELETE_PROJECT) {
					handleDeleteProjectAction(target);
				}

			}

			public Action[] getActions(Object target, Object sender) {
				if (securityManager.getCurrentUser().getSystemRole() == RolesEnum.LECTOR) {
					return null;
				}
				
				if (target == null) {
					return null;
				} else if (container.getParent(target) != null) {
					if (treetable.areChildrenAllowed(target)) {
						return new Action[] { ADD };
					} else {
						return new Action[] { DELETE };
					}
				}
				if (container.getParent(target) == null) {
					return new Action[] { DELETE_PROJECT };
				}
				return null;
			}
		});

		treetable.addListener(new ItemClickListener() {

			private static final long serialVersionUID = 1L;

			@Override
			public void itemClick(ItemClickEvent event) {

				Item item = treetable.getItem(event.getItemId());
				if (item != null) {
					User userObject = (User) item.getItemProperty("user")
							.getValue();
					if (userObject != null) {
						getWindow().showNotification(
								TaskManagerNotification.showTableNotification(
										"user info", userObject));
					}
				}
			}
		});
	}

	public Tree getTreetable() {
		return treetable;
	}

	public void setTreetable(Tree treetable) {
		this.treetable = treetable;
	}

	@AutoGenerated
	private AbsoluteLayout buildMainLayout() {
		// common part: create layout
		mainLayout = new AbsoluteLayout();
		mainLayout.setImmediate(false);
		mainLayout.setWidth("100%");
		mainLayout.setHeight("100%");
		mainLayout.setMargin(false);

		// top-level component properties
		setWidth("100.0%");
		setHeight("100.0%");

		// verticalLayout_1
		verticalLayout_1 = buildVerticalLayout_1();
		mainLayout.addComponent(verticalLayout_1, "top:0.0px;left:0.0px;");

		return mainLayout;
	}

	@AutoGenerated
	private VerticalLayout buildVerticalLayout_1() {
		// common part: create layout
		verticalLayout_1 = new VerticalLayout();
		verticalLayout_1.setImmediate(false);
		verticalLayout_1.setWidth("100.0%");
		verticalLayout_1.setHeight("100.0%");
		verticalLayout_1.setMargin(false);

		// label_1
		label_1 = new Label();
		label_1.setImmediate(false);
		label_1.setWidth("-1px");
		label_1.setHeight("25px");
		label_1.setValue("Projects");
		verticalLayout_1.addComponent(label_1);
		verticalLayout_1.setComponentAlignment(label_1, 15, 5);

		return verticalLayout_1;
	}
	
	private void handleAddAction(final Object target) {
		
		Object parent = container.getParent(target);

		Project assignedProject = (Project) treetable
				.getItem(parent).getItemProperty("project")
				.getValue();
		List<UserProjectRoles> list = userProjectRolesService
				.getUsersByRoleOnProject(assignedProject,
						rolesService.getRoleById(1L));
		List<User> managers = new ArrayList<User>();

		for (UserProjectRoles upr : list) {
			managers.add(upr.getIdUser());
		}

		if (managers.contains(securityManager.getCurrentUser())) {
			final List<User> selectedUsers = new ArrayList<User>();
			selectedUsers.clear();

			final Window addUserWindowModal = new Window(
					"Select users want to asign to project");
			addUserWindowModal.setWidth("370px");
			addUserWindowModal.setHeight("330px");
			addUserWindowModal.setModal(true);
			
			// all users tab
			HorizontalLayout allUsersLayout = new HorizontalLayout();
			allUsersLayout.setMargin(true);
			allUsersLayout.setSpacing(true);

			List<User> allUsers = new ArrayList<User>();
			allUsers.addAll(userService.getAllUser());

			final ListSelect selectAllUser = new ListSelect();
			selectAllUser.addContainerProperty("user", User.class,
					null);
			for (User u : allUsers) {
				Object ob = selectAllUser.addItem();
				selectAllUser.getItem(ob).getItemProperty("user")
						.setValue(u);
				selectAllUser.setItemCaption(ob, u.getName() + " "
						+ u.getSurname());
			}
			selectAllUser.setMultiSelect(true);
			selectAllUser.setImmediate(true);
			selectAllUser.setNullSelectionAllowed(true);
			selectAllUser.setWidth("170px");

			allUsersLayout.addComponent(selectAllUser);

			Button submit = new Button("Assign");
			submit.addListener(new Button.ClickListener() {

				private static final long serialVersionUID = 1L;

				@SuppressWarnings("unchecked")
				@Override
				public void buttonClick(ClickEvent event) {

					for (Integer i : (Collection<Integer>) selectAllUser
							.getValue()) {
						User user = (User) selectAllUser.getItem(i)
								.getItemProperty("user").getValue();
						selectedUsers.add(user);
					}

					for (User u : selectedUsers) {

						if (u != null) {
							Object parent = container
									.getParent(target);
							Project project = (Project) container
									.getItem(parent)
									.getItemProperty("project")
									.getValue();
							Roles role = (Roles) container
									.getItem(target)
									.getItemProperty("role")
									.getValue();

							List<UserProjectRoles> existingRecords = new ArrayList<UserProjectRoles>();

							if (userProjectRolesService
									.getExistingRecord(project, u,
											role) != null) {
								existingRecords
										.addAll(userProjectRolesService
												.getExistingRecord(
														project, u,
														role));
							}

							if (existingRecords.isEmpty()) {

								Object item = treetable
										.getContainerDataSource()
										.addItem();
								treetable.setParent(item, target);
								treetable.setChildrenAllowed(item,
										false);
								container.getItem(item)
										.getItemProperty("user")
										.setValue(u);
								treetable.setItemCaption(
										item,
										container
												.getItem(item)
												.getItemProperty(
														"user")
												.getValue()
												.toString());

								// insert to DB
								UserProjectRoles upr = new UserProjectRoles();
								upr.setIdProject(project);
								upr.setIdRole(role);
								upr.setIdUser(u);

								userProjectRolesService
										.insertUserProjectRoles(upr);
							} else {
								Notification error = new Notification(
										"Error",
										"User "
												+ u
												+ " already assigned to project",
										Notification.TYPE_ERROR_MESSAGE);
								getWindow().showNotification(error);
							}
						}
					}
					(addUserWindowModal.getParent())
							.removeWindow(addUserWindowModal);
				}
			});
			allUsersLayout.addComponent(submit);

			// not assigned users tab
			HorizontalLayout notAssignedUsersLayout = new HorizontalLayout();
			notAssignedUsersLayout.setMargin(true);
			notAssignedUsersLayout.setSpacing(true);

			ListSelect selectNotAssignedUser = new ListSelect();
			for (User u : allUsers) {
				if (!u.isActivated()) {
					selectNotAssignedUser.addItem(u);
				}
			}
			selectNotAssignedUser.setMultiSelect(true);
			selectNotAssignedUser.setImmediate(true);
			selectNotAssignedUser.setNullSelectionAllowed(true);
			selectNotAssignedUser.setWidth("170px");

			notAssignedUsersLayout
					.addComponent(selectNotAssignedUser);

			Button submitBtn = new Button("Assign");
			submitBtn.addListener(new Button.ClickListener() {

				private static final long serialVersionUID = 1L;

				@SuppressWarnings("unchecked")
				@Override
				public void buttonClick(ClickEvent event) {
					for (Integer i : (Collection<Integer>) selectAllUser
							.getValue()) {
						User user = (User) selectAllUser.getItem(i)
								.getItemProperty("user").getValue();
						selectedUsers.add(user);
					}

					for (User u : selectedUsers) {
						if (u != null) {
							Object item = treetable
									.getContainerDataSource()
									.addItem();
							treetable.setParent(item, target);
							treetable.setChildrenAllowed(item,
									false);
							container.getItem(item)
									.getItemProperty("user")
									.setValue(u);
							treetable
									.setItemCaption(
											item,
											container
													.getItem(item)
													.getItemProperty(
															"user")
													.getValue()
													.toString());

							Object parent = container
									.getParent(target);
							Project project = (Project) container
									.getItem(parent)
									.getItemProperty("project")
									.getValue();
							Roles role = (Roles) container
									.getItem(target)
									.getItemProperty("role")
									.getValue();

							// insert to DB
							UserProjectRoles upr = new UserProjectRoles();
							upr.setIdProject(project);
							upr.setIdRole(role);
							upr.setIdUser(u);

							userProjectRolesService
									.insertUserProjectRoles(upr);
						}
					}
					(addUserWindowModal.getParent())
							.removeWindow(addUserWindowModal);
				}
			});
			notAssignedUsersLayout.addComponent(submitBtn);

			// tabs in modal window
			VerticalLayout v = new VerticalLayout();
			TabSheet tabs = new TabSheet();
			tabs.addTab(allUsersLayout, "All users");
			tabs.addTab(notAssignedUsersLayout,
					"Not assigned users");
			v.addComponent(tabs);

			// modal window
			addUserWindowModal.addComponent(v);
			getWindow().addWindow(addUserWindowModal);
		} else {
			Notification error = new Notification("Error",
					"You are not allowed to manage users in case that you are not the Manager of project!",
					Notification.TYPE_ERROR_MESSAGE);
			getWindow().showNotification(error);
		}
	}

	private void handleDeleteAction(final Object target) {

		Object parent = container.getParent(target);
		Object project = container.getParent(parent);

		Project assignedProject = (Project) treetable
				.getItem(project).getItemProperty("project")
				.getValue();
		List<UserProjectRoles> list = userProjectRolesService
				.getUsersByRoleOnProject(assignedProject,
						rolesService.getRoleById(1L));
		List<User> managers = new ArrayList<User>();

		for (UserProjectRoles upr : list) {
			managers.add(upr.getIdUser());
		}

		if (managers.contains(securityManager.getCurrentUser())) {
			User selectedUser = (User) container.getItem(target)
					.getItemProperty("user").getValue();
			Roles selectedUserRole = (Roles) treetable
					.getItem(parent).getItemProperty("role")
					.getValue();
			Project selectedUserProject = (Project) treetable
					.getItem(project).getItemProperty("project")
					.getValue();

			List<Task> tasks = taskService
					.getTasksOnProjectWithUser(selectedUser,
							selectedUserProject);
			if (tasks == null) {
				// remove from DB
				UserProjectRoles upr = userProjectRolesService
						.getExistingRecord(selectedUserProject,
								selectedUser, selectedUserRole)
						.get(0);
				userProjectRolesService.deleteUserProjectRoles(upr
						.getIdThis());

				// remove from tree
				treetable.removeItem(target);
			} else {
				Notification error = new Notification("Error",
						"User has some tasks on project",
						Notification.TYPE_ERROR_MESSAGE);
				getWindow().showNotification(error);
			}

		} else {

			Notification error = new Notification("Error",
					"You are not allowed to delete user",
					Notification.TYPE_ERROR_MESSAGE);
			getWindow().showNotification(error);

		}
	}
	
	private void handleDeleteProjectAction(final Object target) {
		Project assignedProject = (Project) treetable
				.getItem(target).getItemProperty("project")
				.getValue();
		List<UserProjectRoles> list = userProjectRolesService
				.getUsersByRoleOnProject(assignedProject,
						rolesService.getRoleById(1L));
		List<User> managers = new ArrayList<User>();

		for (UserProjectRoles upr : list) {
			managers.add(upr.getIdUser());
		}

		if (managers.contains(securityManager.getCurrentUser())) {

			projectService.deleteProjects(assignedProject);
			removeItemFromTree(assignedProject);
			mainPage.removeProject(assignedProject);
			
			Notification error = new Notification("Information",
					"Project " + assignedProject.getName() + " was deleted!",
					Notification.TYPE_HUMANIZED_MESSAGE);
			getWindow().showNotification(error);
			
		} else {
			Notification error = new Notification("Error",
					"You are not allowed to delete project!",
					Notification.TYPE_ERROR_MESSAGE);
			getWindow().showNotification(error);
		}
	}
} 